-
Notifications
You must be signed in to change notification settings - Fork 100
Conversation
type ResolvedOfferings struct { | ||
VolumeSize *resource.Quantity `json:"volumeSize,omitempty"` | ||
Volumes map[string]VolumeResolvedOffering `json:"volumes,omitempty"` | ||
Containers map[string]ContainerResolvedOffering `json:"containers,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of storing a map of container name to memory request, we're storing a map of container name to a struct containing the following info:
- memory request
- computeclass name
- cpuscaler value
if offerings := resolvedOfferingsAnnotation(appInstance, container); offerings != "" { | ||
annotations[labels.AcornContainerResolvedOfferings] = offerings | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to put this annotation onto the ContainerReplica so that I can determine the name of the container's ComputeClass in something else I am working on, where the only info that I have is the ContainerReplica and not the corresponding AppInstance.
pkg/controller/defaults/memory.go
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed this file to computeclass.go and heavily modified it, so git just thinks I deleted it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this test no longer tests anything useful so I just deleted it
func TestVolumeClassDefaultsSet(t *testing.T) { | ||
tester.DefaultTest(t, scheme.Scheme, "testdata/volumeclass/volume-class-defaults-set", Calculate) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test was no longer useful; deleted
pkg/controller/appdefinition/testdata/volumes/cluster-default-with-bind-combos/expected.golden
Outdated
Show resolved
Hide resolved
d06e018
to
dcafa98
Compare
a011bdb
to
3da48c0
Compare
Signed-off-by: Grant Linville <[email protected]>
3da48c0
to
4aca73a
Compare
} else { | ||
in.Status.Defaults.Region = "" | ||
} | ||
in.Status.ResolvedOfferings.Region = region |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intention here was that we only set the region here if it is blank. Some of our code relies on this (e.g. I can call SetDefaultRegion
as many times as I want and it will do the right thing).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thedadams let me know if this function looks good to you now. I am still a little bit confused as to how it is supposed to work to be honest.
data, _ := convert.EncodeToMap(resolved) | ||
j, _ := json.Marshal(data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big fan of ignoring errors here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 yeah, should always handle error in case of bad inputs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/controller/appdefinition/testdata/volumes/cluster-default-with-bind-combos/input.yaml
Outdated
Show resolved
Hide resolved
@@ -258,7 +258,7 @@ func (s *Validator) ValidateUpdate(ctx context.Context, obj, old runtime.Object) | |||
} | |||
} | |||
|
|||
if newParams.Spec.Region != oldParams.Spec.Region && newParams.Spec.Region != oldParams.Status.Defaults.Region { | |||
if newParams.Spec.Region != oldParams.Spec.Region && newParams.Spec.Region != oldParams.Status.ResolvedOfferings.Region { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
if newParams.Spec.Region != oldParams.Spec.Region && newParams.Spec.Region != oldParams.Status.ResolvedOfferings.Region { | |
if newParams.Spec.Region != oldParams.Status.ResolvedOfferings.Region { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't go with the suggestion because it caused update validation issues, but I did modify this line. Let me know what you think.
pkg/volume/volume.go
Outdated
// Order of precedence: | ||
// 1. VolumeResolvedOffering - the previously resolved values for Class, Size, and AccessModes | ||
// 2. VolumeBinding - the values set by the user in the app spec | ||
// 3. VolumeRequest - the defaults as defined in the acorn image |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Volume bindings are the ones set by the user at runtime (with the -v
flag). I think these are the top precedence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're correct. I completely reworked this function.
data, _ := convert.EncodeToMap(resolved) | ||
j, _ := json.Marshal(data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 yeah, should always handle error in case of bad inputs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took a look over and the implementation looks correct. I do want to give this a test in my side but approving so you're not blocked on your other work.
} | ||
} | ||
pvc.Spec.Resources.Requests[corev1.ResourceStorage] = defaultSize | ||
pvc.Spec.Resources.Requests[corev1.ResourceStorage] = *v1.DefaultSize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the above validation no longer required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why I removed that, lol. I'll add it back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait, nvm. The reason I removed that is because the refactored ResolveVolumeRequest function (called earlier here) will handle setting the default size and checking to see if there is already a size that was previously resolved. So by the time we get down here, if there is still no determined size, the only thing left to use is v1.DefaultSize
.
Signed-off-by: Grant Linville <[email protected]>
if in.Spec.Region != "" && in.Status.ResolvedOfferings.Region == "" { | ||
in.Status.ResolvedOfferings.Region = in.Spec.Region | ||
} else { | ||
in.Status.ResolvedOfferings.Region = region |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic isn't quite right. For example, if spec.region
and status.resolvedOfferings.region
are both not empty, then status.resolvedOfferings.region
gets set to the passed in region
.
I think this is correct:
if in.Spec.Region != "" && in.Status.ResolvedOfferings.Region == "" { | |
in.Status.ResolvedOfferings.Region = in.Spec.Region | |
} else { | |
in.Status.ResolvedOfferings.Region = region | |
if in.Spec.Region != "" { | |
in.Status.ResolvedOfferings.Region = in.Spec.Region | |
} else if in.Status.ResolvedOfferings.Region == "" { | |
in.Status.ResolvedOfferings.Region = region |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reworked it a little bit. Let me know if you think it looks good. I'm still kinda confused about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, I think what I suggested is simpler. However, what you have does the job.
|
||
bound := volumeBindings[name].Volume != "" | ||
|
||
if _, alreadySet := app.Status.ResolvedOfferings.Volumes[name]; !alreadySet && !bound { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes it seem like it is not possible to change a volume's settings. For example, if a volume as been resolved and is alreadySet
, then would it be possible to change its size or access modes?
The difference of what this did before was that it was only calculating the defaults, and we decided that the defaults for a volume shouldn't change because it causes too many issues. However, now this is the completely "resolved" volume information, which should be allowed to change if the user tries to change it via an Acornfile update (I think your logic allows the user to change volume information via the command line).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good point. I will work on fixing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, from what I understand, you cannot change the access modes of an existing PVC in Kubernetes, but you can increase its size. I heavily modified this function so that the size can be changed even if the volume offering has been previously resolved, but the volume class and access modes cannot be changed after the volume is created. Let me know if it looks good to you. From my testing, everything seems to me to be working properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem to set a different size if a volume is alreadySet
and not bound
.
pkg/volume/volume.go
Outdated
@@ -151,24 +151,30 @@ func getVolumeClassNames(volumeClasses map[string]adminv1.ProjectVolumeClassInst | |||
return typed.SortedKeys(storageClassName) | |||
} | |||
|
|||
func CopyVolumeDefaults(volumeRequest v1.VolumeRequest, volumeBinding v1.VolumeBinding, volumeDefaults v1.VolumeDefault) v1.VolumeRequest { | |||
func ResolveVolumeRequest(volumeRequest v1.VolumeRequest, volumeBinding v1.VolumeBinding, resolvedVolume v1.VolumeResolvedOffering) v1.VolumeRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous iteration of this function had one responsibility: to put the request, binding and default together to get a merged volume request for the volume to process.
It seems that now this doesn't completely "resolve" the volume. It resolves the request without the defaults and the default information is added later, if needed. In other words, it kind of only does have the job now.
My opinion, which can be completely disregarded, is that passing the default information here and using it to complete "resolve" the volume would be better. Some care would need to be taken so that this function can be uses in the various places it is being used, but I think it would make it more complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reworked the function to fully resolve the volume based on the previously resolved values, all compute class information, bindings specified by the user, etc. Thankfully it didn't require too many modifications in the other places where this function is called. I agree that it is better this way.
Signed-off-by: Grant Linville <[email protected]>
Signed-off-by: Grant Linville <[email protected]>
Signed-off-by: Grant Linville <[email protected]>
Signed-off-by: Grant Linville <[email protected]>
Signed-off-by: Grant Linville <[email protected]>
func podAnnotations(appInstance *v1.AppInstance, container v1.Container) map[string]string { | ||
annotations := map[string]string{ | ||
labels.AcornContainerSpec: containerAnnotation(container), | ||
} | ||
addPrometheusAnnotations(annotations, container) | ||
|
||
offerings, err := resolvedOfferingsAnnotation(appInstance, container) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this error is still not handled...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Below this line there is a check for if err == nil
, and then we attach the annotation. I don't actually want to return this error if it happens, since we can safely just ignore it and keep going.
@@ -52,23 +52,23 @@ type AppInstance struct { | |||
} | |||
|
|||
func (in *AppInstance) HasRegion(region string) bool { | |||
return in.Status.Defaults.Region == region || in.Spec.Region == region | |||
return in.Status.ResolvedOfferings.Region == region || in.Spec.Region == region |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return in.Status.ResolvedOfferings.Region == region || in.Spec.Region == region | |
return in.Status.ResolvedOfferings.Region == region |
if in.Status.ResolvedOfferings.Region != "" { | ||
return in.Status.ResolvedOfferings.Region | ||
} | ||
return in.Status.Defaults.Region | ||
return in.Spec.Region |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can just return in.Status.ResolvedOfferings.Region
here.
|
||
bound := volumeBindings[name].Volume != "" | ||
|
||
if _, alreadySet := app.Status.ResolvedOfferings.Volumes[name]; !alreadySet && !bound { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem to set a different size if a volume is alreadySet
and not bound
.
Signed-off-by: Grant Linville <[email protected]>
This reverts commit dbd950d.
This reverts commit dbd950d. Signed-off-by: Grant Linville <[email protected]>
This reverts commit dbd950d. Signed-off-by: Grant Linville <[email protected]>
This reverts commit 8b9acb4.
Overview
This change refactors
AppInstance.Status.Defaults
toAppInstance.Status.ResolvedOfferings
. This field used to store the default values for container memory requirements, the region, and volumeclass information for the AppInstance. With these changes, the ResolvedOfferings stores the actual value of the app's region, computeclass information for each container in the app (rather than just memory information), and volumeclass information for each volume. Now it is the source of absolute truth, and there is no need to compareAppInstance.Spec
(overrides from the user),AppInstance.Status.AppSpec
(defaults from the acorn image), andAppInstance.Status.Defaults
(defaults from volume and compute classes) like we used to.This is a breaking API change. I have updated all of the unit tests in here to reflect that change. (Sorry, there are a lot of them.) I believe this will not cause deployed apps to restart, but they will not get the status updates until they are processed again by the controller (which requires their generation to increase). If we want them to all restart and get the status updates as soon as this runtime change rolls out, I can do that pretty easily as well.
Checklist
This is a title (#1216)
. Here's an example